module GYLite {
	export class AtlasManager {
		private _atlasVec:Array<AtlasRect>;
		private _atlasId:number;//图集id
		/**允许同时缓存的图集数量，默认10*/public maxAtlasNum:number = 20;
		/**创建图集的宽度*/public atlasWidth:number=2048;
		/**创建图集的高度*/public atlasHeight:number=2048;
		public constructor() {
			this._atlasVec = [];
			this._atlasId = 0;
			window["test_drawToCanvas"] = this.outputAtlas.bind(this);
			PoolUtil.setPoolLengthWarn(AtlasRect, 10000);
		}
		public get atlasNum():number
		{
			return this._atlasId;
		}
		/**获取图集矩形数组*/
		public get atlasVec():Array<AtlasRect>
		{
			return this._atlasVec;
		}
		/**从图集管理器的图集队列中移除图集*/
		public removeAtlas(atlasRect:AtlasRect):void
		{
			let ind:number;
			let s= this;
			ind = s._atlasVec.indexOf(atlasRect);
			if(ind > -1)
			{				
				s._atlasVec.splice(ind,1);
			}
		}
		/**插入纹理
		 * @param texName 小图名称
		 * @param atlasName 图集名称
		 * @param w 图片宽度
		 * @param h 图片高度
		 * @param type 裁剪策略 排列方式0 偏向正方形 1 优先横向 2 优先纵向,默认1
		 * @param gap 图片之间的间隙，默认1
		*/
		public addTexture(texName:string,atlasName:string,w:number,h:number,type:number = 1,gap:number=1):{atlasRect:AtlasRect,atlasInfo:AtlasInfo,error:SysError}
		{
			let i:number,len:number;
			let rect:AtlasRect;						
			let s =this;
			let result:{atlasRect:AtlasRect,atlasInfo:AtlasInfo,error:SysError};
			result = {atlasRect:null,atlasInfo:null,error:null};
			if(w > AtlasRect.maxSize || h > AtlasRect.maxSize)
			{
				result.error = SysError.ATLAS_SIZE_LIMIT.throwError([atlasName,w,h]);
				return result;
			}
			//遍历已有图集，找到同名的获取子级区域，如果空间不足则报异常
			len = s._atlasVec.length;
			if(len > 0)
			{				
				for(i=0;i<len;++i)
				{
					if(s._atlasVec[i].atlasName != atlasName)
						continue;
					rect = s._atlasVec[i].cutRect(w,h,type,gap);
					if(rect)
					{
						rect.name = texName;
						result.atlasInfo = new AtlasInfo(rect.atlasName,rect.atlasId,s._atlasVec[i].width,s._atlasVec[i].height,new RectInfo(rect.name,rect.x,rect.y,rect.width,rect.height,rect.gap))						
						return result;
					}
					else
					{
						result.error = SysError.ATLAS_INSERT_SIZE_LIMIT.throwError([atlasName,texName,w,h]);				
						return result;
					}
				}
			}			
			//超出图集数量上限
			if(len == s.maxAtlasNum)
			{				
				result.error = SysError.ATLAS_NUM_LIMIT.throwError([atlasName,texName]);				
				return result;
			}
			let atlasResult:{atlasRect:AtlasRect,error:SysError};
			atlasResult = s.createAtlas(s.atlasWidth,s.atlasHeight,atlasName);
			result.atlasRect = atlasResult.atlasRect;
			rect = atlasResult.atlasRect.cutRect(w,h,type,gap);
			rect.name = texName;
			result.atlasInfo = new AtlasInfo(atlasName,rect.atlasId,s.atlasWidth,s.atlasHeight,new RectInfo(rect.name,rect.x,rect.y,rect.width,rect.height,rect.gap));			
			return result;
		}
		/**创建一个虚拟图集
		 * @param w 宽度
		 * @param h 高度
		 * @param atlasName 图集名称		 
		*/
		public createAtlas(w:number,h:number,atlasName:string,result:{atlasRect:AtlasRect,error:SysError}=null,check:boolean=false):{atlasRect:AtlasRect,error:SysError}
		{
			let rect:AtlasRect;
			let len:number;
			let s= this;			
			result = result?result:{atlasRect:null,error:null};
			if(check)
			{
				len = s._atlasVec.length;
				if(len > 0)
				{				
					while(--len>-1)					
					{
						if(s._atlasVec[len].atlasName == atlasName)
						{
							result.atlasRect = s._atlasVec[len];
							result.error = SysError.ATLAS_DUPLICATE.throwError([atlasName]);
							return result
						}
							
					}
				}
			}
			rect = s._atlasVec[s._atlasVec.length] = new AtlasRect(0,0,w,h,s);
			result.atlasRect = rect;
			rect.emptyRects = [rect];
			rect.textureRects = [];
			rect.atlasName = atlasName;
			rect.atlasId = s._atlasId++;			
			return result;
		}
		/**删除纹理
		 * @param texName 小图名称
		*/
		public removeTexture(texName:string):void
		{
			let len:number;
			let rect:AtlasRect;
			let s = this;
			len = s._atlasVec.length;
			while(--len>-1)
			{
				rect = s._atlasVec[len].findTextureRect(texName);
				if(rect)
				{
					rect.backToEmpty();
					return;
				}
			}
			// throw(new Error("移除不存在的纹理！" + texName));
		}
		private createSheetJson():any[]
		{
			let json:any;
			let i:number,len:number,j:number,len2:number;
			let s = this;
			let arr:AtlasRect[],arr2:any[];			
			let rect:AtlasRect;
			let x:number,y:number,w:number,h:number;
			arr2 = [];			
			len = s._atlasVec.length;
			for(i=0;i<len;++i)
			{				
				arr = s._atlasVec[i].textureRects;
				json = {"file":s._atlasVec[i].resKey,"frames":{}};
				arr2.push(json);
				len2 = arr.length;				
				for(j=0;j<len2;++j)
				{	
					rect = arr[i];
					x = rect.x + rect.gap;
					y = rect.y + rect.gap;
					w = rect.textureWidth;
					h = rect.textureHeight;
					json.frames[rect.name] = {"x":x,"y":y,"w":w,"h":h,"offX":0,"offY":0,"sourceW":w,"sourceH":h};				
				}
			}
			return arr2;	
		}
		public cvs:HTMLCanvasElement;
		public ctx:CanvasRenderingContext2D;
		private _atlasCount:number = 0;		
		public outputAtlasArr:any[];		
		private _fileReader:FileReader;
		/**输出图集数据文件
		 * @param show 是否显示到body上
		 * @param callBack 完成回调 ():void=>{}
		 * @param thisObj this指向
		 * @param reset 默认true，不需要设置
		*/
		public outputAtlas(show:boolean=false,callBack:Function,thisObj:any,reset:boolean=true):void
		{let s =this;
			
			let json:any;
			let i:number,len:number,j:number,len2:number;
			let arr:AtlasRect[];
			let x:number,y:number,w:number,h:number;
			let resObj:ResObject;
			let rect:AtlasRect;			
            if(s._fileReader == null)
                s._fileReader = new FileReader;			
			if(reset)
				s.outputAtlasArr = [];
			if(s._atlasVec == null)
			{
				if(callBack!=null)
					callBack.call(thisObj);
				return;
			}
			if(s.ctx == null)
			{
				 s.cvs = document.createElement("canvas");
				 s.ctx = s.cvs.getContext("2d");
			}				 
			s.cvs.width = 2048;
			s.cvs.height = 2048;
			if(s.cvs.parentNode == null && show)
			{
				s.cvs.style.position = "absolute";
				s.cvs.style.left = "300px";
				s.cvs.style.pointerEvents = "none";
				document.body.appendChild(s.cvs);
			}				
			// s._atlasCount = len = s._atlasVec.length;
			if(s._atlasCount == 0)
				s._atlasCount = s._atlasVec.length;
			if(s._atlasCount == 0)
			{
				if(callBack!=null)
					callBack.call(thisObj);
				return;
			}
			
			i= s._atlasCount - 1;
			arr = s._atlasVec[i].textureRects;
			json = {"file":s._atlasVec[i].resKey,"frames":{}};
			s.ctx.clearRect(0,0,s.cvs.width,s.cvs.height);
			len2 = arr.length;
			for(j=0;j<len2;++j)
			{
				rect = arr[j];
				resObj = GYLite.GYLoader.getRes(rect.name,rect.resKey);
				if(!resObj)
				{
					console.warn("查询到空图集区域!"+rect.name+"-"+rect.atlasName);
					rect.backToEmpty();
					continue;
				}
				x = rect.x + rect.gap;
				y = rect.y + rect.gap;
				w = rect.textureWidth;
				h = rect.textureHeight;
				json.frames[rect.name] = {"x":x,"y":y,"w":w,"h":h,"offX":0,"offY":0,"sourceW":w,"sourceH":h};
				let res:egret.Texture = resObj.res;
				s.ctx.drawImage(res.bitmapData.source,0,0,w,h,x,y,w,h);
			}				
			let b:GYLite.GYByteArray = new GYLite.GYByteArray();				
			let obj:any;
			obj = {json:json,jsonBytes:b,atlasBytes:null};
			b.writeUTFBytes(JSON.stringify(json));
			b.position = 0;
			s.outputAtlasArr.push(obj);
			s.cvs.toBlob((result)=>{
				
				s._fileReader.readAsArrayBuffer(result);
				s._fileReader.onload = function(e):void
				{						
					obj.atlasBytes = new GYLite.GYByteArray(<ArrayBuffer>(<FileReader>e.currentTarget).result);
					--s._atlasCount;
					if(s._atlasCount == 0)
					{
						if(callBack!=null)
							callBack.call(thisObj);
					}
					else
						s.outputAtlas(show,callBack,thisObj,false);
				}
				
			},"image/png");
					
		}
		/**输入虚拟图集数据*/
		public inputJson(atlasArray:any[]):void
		{
			let i:number,len:number;
			let s = this;
			let rect:AtlasRect;
			len = atlasArray.length;
			for(i=0;i<len;++i)
			{
				rect = s._atlasVec[i] = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
				rect.emptyRects = [];
				rect.textureRects = [];
				rect.atlasName = atlasArray[i].atlasName;
				rect.atlasId = atlasArray[i].altasId;
				rect.inputJson(atlasArray[i]);
			}
		}
		/**输出虚拟图集数据*/
		public outputJson():any[]
		{
			let i:number,len:number;
			let s = this;
			let arr:any[];
			arr = [];
			len = s._atlasVec.length;
			for(i=0;i<len;++i)
			{
				arr.push(s._atlasVec[i].outputJson());
			}
			return arr;
		}
	}
}